/***************************************************************************
 *      main.cpp
 * 
 *      Description: The main program file
 *		
 *      Copyright 2012 Artem Korzhimanov <korzhimanov.artem@gmail.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 ***************************************************************************/

#ifdef _OPENMP
#include <omp.h>
#endif

#include "solver.h"
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <ctime>

using namespace std;

double invcps = 1./(double)CLOCKS_PER_SEC;
double get_time()
{
#ifdef _OPENMP
	return omp_get_wtime();
#else
	return clock()*invcps;
#endif
}

void WrongArguments()
{
	cout << "Wrong arguments. Type -h for help." << endl; exit(-1);
}

int main(int argc, char **argv)
{
	char input_file_name[512];
	sprintf(input_file_name, "input.py");
	
	if (argc > 1)
	{
		int i = 1;
		do
		{
			if (!strcmp(argv[i], "-i"))
			{
				if (argc > i+1)
					strcpy(input_file_name, argv[++i]);
				else
					WrongArguments();
				cout << "Input file name has been setted to " << argv[i] << endl;
				i++; continue;
			}
			if (!strcmp(argv[i], "-h"))
			{
				cout << "Usage: vlasov [OPTION...]" << endl;
				cout << setw(20) << left << "  -i <name>" << "задаёт произвольное имя входного файла" << endl;
				cout << setw(20) << left << "  -h" << "выводит эту подсказку" << endl;
				exit(0);
			}
			WrongArguments();
		}
		while (i < argc);
	}	
		
	
	// initializing solver
	Solver S(input_file_name);
	
	S.InitFields();
	S.InitPlasma();
	S.InitTestParticles();

	S.CreateDirs();

	S.SaveInput("input_parameters");
	S.InitOutput("output");

	double t0 = get_time();
/*	char *s = new char[256];
	strcpy(s, S.main_dir);
	strcat(s, "cout.out");
	ofstream cout(s);
	delete[] s;
*/	cout << setw(10) << "LongField" << setw(11) << "TransField" << setw(10) << "FieldGen" << setw(10) << "DstrFunc" << setw(10) << "Particles" << setw(10) << "SvFields" << setw(10) << "SvConcs" << setw(10) << "SvDstr" << setw(10) << "SvOutput" << setw(10) << "Step" << setw(20) << "Passed/ Estimated" << endl;

	double t1, t2, t;
	cout << fixed << setprecision(4);
	for (int k = 0; k < S.mesh->MAX_T; k++)
	{
		// LongField
		t = t1 = get_time();
		S.CalcLongFields();
		t2 = get_time();
		cout << setw(10) << (t2-t1);

		// TransField
		t1 = t2;
		S.CalcSources( (double)k*S.mesh->dt );
		S.CalcTransFields();
		t2 = get_time();
		cout << setw(11) << (t2-t1);

		// FieldGen
		t1 = t2;
		S.FieldGeneration();
		t2 = get_time();
		cout << setw(10) << (t2-t1);

		// DstrFunc
		t1 = t2;
		S.CalcDstrFunc();
		t2 = get_time();
		cout << setw(10) << (t2-t1);

		// Particles
		t1 = t2;
		if (S.NUM_PRT > 0) S.MoveParticles();
		t2 = get_time();
		cout << setw(10) << (t2-t1);

		// SvFields
		t1 = t2;
		S.SaveFields( k );
		t2 = get_time();
		cout << setw(10) << (t2-t1);

		// SvConcs
		t1 = t2;
		S.SaveConcs( k );
		t2 = get_time();
		cout << setw(10) << (t2-t1);

		// SvDstr
		t1 = t2;
		S.SaveDstrFunc( k );
		t2 = get_time();
		cout << setw(10) << (t2-t1);

		// Output
		t1 = t2;
		//S.SaveOutput( k, "output");
		t2 = get_time();
		cout << setw(10) << (t2-t1);
		cout << setw(10) << (t2-t );
		cout << setprecision(2);
		cout << setw(9) << (t2-t0) << "/ " << (t2-t0)/(k+1)*(S.mesh->MAX_T) << endl;
		cout << setprecision(4);
//		cout << setw(7) << k << " " << setw(10) << (t2-t0) << " s/ " << setw(10) << (t2-t0)/(k+1)*(S.mesh->MAX_T) << " s" << endl;
	}

	//S.SaveResults();
	
	cout << "Done!" << endl;
	t = get_time();
	cout << "Full time: " << (t-t0) << " s (" << (t-t0)/S.mesh->MAX_T << " s per iteration)" << endl;
//	cout.close();

	return 0;
}
